<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>
      Zoom to extent of all features | Sample | ArcGIS API for JavaScript 4.17
    </title>

    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.17/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/4.17/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

    <script>
      require([
        "esri/Map",
        "esri/views/SceneView",
        "esri/layers/FeatureLayer",
        "esri/widgets/LayerList",
        "esri/core/Collection"
      ], function (Map, SceneView, FeatureLayer, LayerList, Collection) {
        var featureLayer = new FeatureLayer({
          outFields: ["STATION_NAME", "COUNTRY", "TEMP"],
          portalItem: {
            // autocasts as new PortalItem()
            id: "3a177da3f6524d61980fb41125b2349c"
          },
          title: "Temperature on Jan, 4, 2017"
        });

        // When the layer is loaded, query for the extent
        // of all features in the layer that satisfy the
        // definitionExpression. Then set the view's
        // extent to the returned extent of all features.

        featureLayer.when(function () {
          featureLayer.definitionExpression = createDefinitionExpression("");
          zoomToLayer(featureLayer);
        });

        var map = new Map({
          basemap: "dark-gray-vector",
          layers: [featureLayer]
        });

        var view = new SceneView({
          container: "viewDiv",
          map: map
        });

        var layerList = new LayerList({
          view: view,
          listItemCreatedFunction: createActions
        });
        view.ui.add(layerList, "top-right");

        // definitionExpressions used by each action
        // listed in the LayerList

        var expressions = new Collection([
          {
            id: "75+",
            expression: "TEMP > 75"
          },
          {
            id: "50-75",
            expression: "TEMP > 50 AND TEMP <=75"
          },
          {
            id: "25-50",
            expression: "TEMP > 25 AND TEMP <=50"
          },
          {
            id: "25-",
            expression: "TEMP <= 25"
          },
          {
            id: "arctic-circle",
            expression: "LATITUDE >= 66.5"
          },
          {
            id: "north-temperate-zone",
            expression: "LATITUDE < 66.5 AND LATITUDE >= 23.5"
          },
          {
            id: "torrid-zone",
            expression: "LATITUDE < 23.5 AND LATITUDE >= -23.5"
          }
        ]);

        // When an action is triggered, the definitionExpression
        // is set on the layer and the view's extent updates
        // to match the features visible in the layer

        layerList.on("trigger-action", function (event) {
          var actionId = event.action.id;
          var layer = event.item.layer;

          var subExpression = expressions.find(function (item) {
            return item.id === actionId;
          }).expression;

          var definitionExpression = createDefinitionExpression(subExpression);
          layer.definitionExpression = definitionExpression;

          zoomToLayer(layer);
        });

        function createActions(event) {
          var item = event.item;

          item.actionsOpen = true;
          item.actionsSections = [
            [
              {
                title: "> 75°F",
                className: "esri-icon-zoom-out-fixed",
                id: "75+"
              },
              {
                title: "50°-75°F",
                className: "esri-icon-zoom-out-fixed",
                id: "50-75"
              },
              {
                title: "25°-50°F",
                className: "esri-icon-zoom-out-fixed",
                id: "25-50"
              },
              {
                title: "< 25°F",
                className: "esri-icon-zoom-out-fixed",
                id: "25-"
              }
            ],
            [
              {
                title: "Above Arctic Circle",
                className: "esri-icon-zoom-out-fixed",
                id: "arctic-circle"
              },
              {
                title: "North Temperate Zone",
                className: "esri-icon-zoom-out-fixed",
                id: "north-temperate-zone"
              },
              {
                title: "Torrid Zone",
                className: "esri-icon-zoom-out-fixed",
                id: "torrid-zone"
              }
            ]
          ];
        }

        // Appends a definitionExpression to a base expression
        // the base expression only returns freatures in
        // Canada, USA, and Mexico. It excludes some US territories
        // located on the other side of the dateline

        function createDefinitionExpression(subExpression) {
          var baseExpression =
            "( COUNTRY LIKE '%United States Of America%' OR " +
            "COUNTRY LIKE '%Canada%' OR " +
            "COUNTRY LIKE '%Mexico%') AND NOT" +
            "(COUNTRY LIKE '%Johnston/Wake/Xmas%' OR " +
            "COUNTRY LIKE '%Hawaii%' OR " +
            "COUNTRY LIKE '%Marshall Islands%' OR " +
            "STATION_NAME = 'Eareckson/Shemya' OR " +
            "COUNTRY LIKE '%Guam%' )";

          return subExpression
            ? baseExpression + " AND (" + subExpression + ")"
            : baseExpression;
        }

        // Zooms to the extent of the layer as defined by
        // its definitionExpression
        // This method will work for all FeatureLayers, even
        // those without a saved `fullExtent` on the service.

        function zoomToLayer(layer) {
          return layer.queryExtent().then(function (response) {
            view.goTo(response.extent).catch(function (error) {
              if (error.name != "AbortError") {
                console.error(error);
              }
            });
          });
        }
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>
